package com.xxx.springboot.interceptor;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.xxx.springboot.annotation.AccessAuth;
import com.xxx.springboot.constant.Constants;
import com.xxx.springboot.exception.NoAuthException;
import com.xxx.springboot.exception.NotLoginException;
import com.xxx.springboot.pojo.UserInfo;

/**
 * 权限校验注解
 */
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    		throws Exception {
        if (handler instanceof HandlerMethod) {
            final HandlerMethod handlerMethod = (HandlerMethod) handler;
            final Method method = handlerMethod.getMethod();
            final Class<?> clazz = method.getDeclaringClass();
            if (clazz.isAnnotationPresent(AccessAuth.class) ||
                    method.isAnnotationPresent(AccessAuth.class)) {
                Object object = request.getSession().getAttribute(Constants.USER_INFO_SESSION_KEY);
                if (null == object) {
                    throw new NotLoginException();
                }
                UserInfo userInfo = (UserInfo) object;
                
                AccessAuth accessAuth = clazz.isAnnotationPresent(AccessAuth.class) ? 
                		clazz.getAnnotation(AccessAuth.class) : method.getAnnotation(AccessAuth.class);

        		String[] permissionCodes = accessAuth.anyPermissionCodes();
                if (null != permissionCodes && permissionCodes.length > 0) {
                    Set<String> permissionCodeSet = new HashSet<>(permissionCodes.length);
                    Arrays.asList(permissionCodes).stream().forEach(code -> permissionCodeSet.add(code));
                    if ((null == userInfo.getPermissionIds())) {
                        throw new NoAuthException();
                    }
                    boolean accessable = permissionCodeSet.stream().anyMatch(
                    		code -> userInfo.getPermissionIds().contains(code));
                    if (!accessable) { // 无权限
                        throw new NoAuthException();
                    }
                    return true;
                }
            }
        }

        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

    }
    
    public static void main(String[] args) {
    	Set<String> permissionIds = new HashSet<>();
    	permissionIds.add("2");
    	permissionIds.add("3");
    	permissionIds.add("1");
    	String[] permissionCodes = new String[]{"1", "2", "3"};
        if (null != permissionCodes && permissionCodes.length > 0) {
            Set<String> permissionCodeSet = new HashSet<>(permissionCodes.length);
            Arrays.asList(permissionCodes).stream().forEach(code -> permissionCodeSet.add(code));
            boolean accessAble = permissionCodeSet.stream().allMatch(
            		code -> permissionIds.contains(code));
            if (!accessAble) {
                System.out.println("false");
            } else {
            	System.out.println("true");
            }
        }
	}
}
